#ifndef _SOCKET_HPP_
#define _SOCKET_HPP_

#include "types.hpp"
#include "jhdefs.hpp"
#include "net/SocketDefs.hpp"
#include "net/SocketImpl.hpp"
#include "stdlib/timespan.hpp"
using JHCPP::stdlib::CTimeSpan;
#include <vector>

NET_NAMESPACE_BEGIN

class CSocket
{
public:
	enum SelectMode
	{
		SELECT_READ  = 1,
		SELECT_WRITE = 2,
		SELECT_ERROR = 4
	};

	typedef std::vector<CSocket> SocketList;

	CSocket();
	CSocket(const CSocket& socket);
	CSocket& operator = (const CSocket& socket);
	virtual ~CSocket();
	bool operator == (const CSocket& socket) const;
	bool operator != (const CSocket& socket) const;
	bool operator <  (const CSocket& socket) const;
	bool operator <= (const CSocket& socket) const;
	bool operator >  (const CSocket& socket) const;
	bool operator >= (const CSocket& socket) const;
	void close();

	static int select(SocketList& readList, SocketList& writeList, SocketList& exceptList, const CTimeSpan& timeout);
	bool poll(const CTimeSpan& timeout, int mode) const;
	int available() const;

	void setSendBufferSize(int size);
	int getSendBufferSize() const;
	void setReceiveBufferSize(int size);
	int getReceiveBufferSize() const;
	void setSendTimeout(const CTimeSpan& timeout);
	CTimeSpan getSendTimeout() const;
	void setReceiveTimeout(const CTimeSpan& timeout);
	CTimeSpan getReceiveTimeout() const;

	void setOption(int level, int option, int value);
	void setOption(int level, int option, unsigned value);
	void setOption(int level, int option, unsigned char value);
	void setOption(int level, int option, const CTimeSpan& value);
	void setOption(int level, int option, const CIPAddress& value);
	void getOption(int level, int option, int& value) const;
	void getOption(int level, int option, unsigned& value) const;
	void getOption(int level, int option, unsigned char& value) const;
	void getOption(int level, int option, CTimeSpan& value) const;
	void getOption(int level, int option, CIPAddress& value) const;

	void setLinger(bool on, int seconds);
	void getLinger(bool& on, int& seconds) const;
	void setNoDelay(bool flag);
	bool getNoDelay() const;
	void setKeepAlive(bool flag);
	bool getKeepAlive() const;
	void setReuseAddress(bool flag);
	bool getReuseAddress() const;
	void setReusePort(bool flag);
	bool getReusePort() const;
	void setOOBInline(bool flag);
	bool getOOBInline() const;
	void setBlocking(bool flag);
	bool getBlocking() const;

	CSocketAddress address() const;
	CSocketAddress peerAddress() const;

	CSocketImpl* impl() const;
	bool secure() const;

	static bool supportsIPv4();
	static bool supportsIPv6();

	void init(int af);

protected:
	CSocket(CSocketImpl* pImpl);
	JH_SOCKET sockfd() const;
	CSocketImpl* m_pImpl;
};

NET_NAMESPACE_END

#endif
